<%@import=lpg.util.DispatchWriter,lpg.util.Utility%>
Predefined Macros:
<%
        for (int i = 0, n = action.localMacroTableSize(); i < n; i++)
        {
            %>
    <%=action.getLocalMacro(i).name()%><%
        }

        //
        // Print the filter macros, if any.
        //
        if (action.filterMacroTableSize() > 0)
        {
            %>


Filter Macros:
<%
            for (int i = 0, n = action.filterMacroTableSize(); i < n; i++)
            {
                %>
    <%=option.escape%><%=action.getFilterMacro(i).name()%><%
            }
        }

        //
        // Print the Exported symbols, if any.
        //
        if (!parser.exports.isEmpty())
        {
            %>


Exported symbols:
<%
            for (int i = 0, n = parser.exports.size(); i < n; i++)
            {
                %>
    <%
                displaySymbol(lexStream.nameString(parser.exports.get(i)));
            }
        }

        //
        // Print the Macro definitions, if any.
        //
        if (!macroTable.isEmpty())
        {
            %>


Defined Symbols:

<%
            for (int i = 0, n = macroTable.size(); i < n; i++)
            {
                MacroSymbol macro = macroTable.element(i);
                int blockToken = macro.block();
                if (blockToken != 0) // a defined macro
                {
                    %>

    <%=macro.name()%>
<%
                    writer.setIndentSize(4);
                    %><%=lexStream.tokenString(blockToken)%>
<%
                    writer.setIndentSize(0);
                }
            }
        }

        //
        // Print the Aliases, if any.
        //
        if (!parser.aliases.isEmpty())
        {
            %>

<%
            if (parser.aliases.size() == 1)
                %>Alias:<%
            else
                %>Aliases:<%
            %>
<%
            for (int i = 0, n = parser.aliases.size(); i < n; i++)
            {
                AliasDefinition alias = parser.aliases.get(i);
                %>
    <%
                writer.beginAutoWrap();
                displaySymbol(lexStream.tokenString(alias.lhsIndex));
                %>::=<%
                displaySymbol(lexStream.tokenString(alias.rhsIndex));
                writer.endAutoWrap();
            }
        }

        //
        // Print special symbols.
        //
        if (!parser.startIndexes.isEmpty())
        {
            %>


Start:
<%
            for (int i = 0, n = parser.startIndexes.size(); i < n; i++)
            {
                %>
    <%
                displaySymbol(grammar.retrieveString(grammar.startSymbol.get(i).symbolIndex()));
            }
        }
        if (parser.identifierIndex != 0)
        {
            %>

Identifier:

    <%
            displaySymbol(grammar.retrieveString(grammar.identifierImage));
        }
        if (parser.eolIndex != 0)
        {
            %>

Eol:

    <%
            displaySymbol(grammar.retrieveString(grammar.eolImage));
        }
        if (parser.eofIndex != 0)
        {
            %>

Eof:

    <%
            displaySymbol(grammar.retrieveString(grammar.eofImage));
        }
        if (parser.errorIndex != 0)
        {
            %>

Error:

    <%
            displaySymbol(grammar.retrieveString(grammar.errorImage));
        }

        //
        // Print the terminals.
        //
        %>

Terminals:
<%
        for (int i = grammar.firstTerminal(); i <= grammar.lastTerminal(); i++)
        {
            if (i != grammar.empty && !grammar.isKeyword(i))
            {
                %>
    <%
                displaySymbol(grammar.retrieveString(i));
            }
        }

        %>


Soft Keywords:
<%
        for (int i = grammar.firstTerminal(); i <= grammar.lastTerminal(); i++)
        {
            if (i != grammar.empty && grammar.isKeyword(i))
            {
                %>
    <%
                displaySymbol(grammar.retrieveString(i));
            }
        }

        //
        // Print the Rules
        //
        %>


Rules:
<%
        //
        // First, print the start rules.
        //
        %>
0<%
        writer.padToColumn(5);
        writer.beginAutoWrap();
        Grammar.RuleElement startRule = grammar.rules.get(0);
        displaySymbol(grammar.retrieveString(startRule.lhs));
        %>::=<%
        displaySymbol(grammar.restoreSymbol(
                grammar.retrieveString(grammar.rhsSym.get(startRule.rhsIndex))));
        writer.endAutoWrap();

        int alternateSpace = 0;
        for (int ruleNo = 1, n = grammar.startSymbol.size(); ruleNo < n; ruleNo++)
        {
            startRule = grammar.rules.get(ruleNo);
            %>
<%=ruleNo%><%
            writer.padToColumn(5);
            writer.beginAutoWrap();
            if (ruleNo > 1)
            {
                writer.padToColumn(alternateSpace);
                %><%=option.orMarker%><%
            }
            else
            {
                displaySymbol(grammar.restoreSymbol(grammar.retrieveString(startRule.lhs)));
                %>::=<%
                alternateSpace = writer.getCurrentColumn() - 2;
            }
            writer.setIndentSize(writer.getCurrentColumn() + 1);

            displaySymbol(grammar.restoreSymbol(
                    grammar.retrieveString(grammar.rhsSym.get(startRule.rhsIndex))));
            displaySymbol(grammar.restoreSymbol(
                    grammar.retrieveString(grammar.rhsSym.get(startRule.rhsIndex + 1))));
            writer.endAutoWrap();
        }

        // leave a gap before listing the remaining rules.
        %>
<%
        //
        // Print the user specified rules.
        //
        for (int ruleIndex = grammar.startSymbol.size(); ruleIndex <= grammar.numRules; ruleIndex++)
        {
            Grammar.RuleElement ruleElement = grammar.rules.get(ruleIndex);
            RuleDefinition rule = parser.rules.get(ruleElement.sourceIndex);
            %>
<%=ruleIndex%><%
            writer.padToColumn(5);
            writer.beginAutoWrap();
            if (ruleElement.isAlternateProduction())
            {
                writer.padToColumn(alternateSpace);
                %><%=option.orMarker%><%
            }
            else
            {
                displaySymbol(lexStream.nameString(rule.lhsIndex));
                int classnameIndex = rule.classnameIndex;
                int arrayElementTypeIndex = rule.arrayElementTypeIndex;
                if (classnameIndex != 0 && arrayElementTypeIndex == 0)
                    %><%=lexStream.nameString(classnameIndex)%><%
                else if (classnameIndex == 0 && arrayElementTypeIndex != 0)
                {
                    %><%=String.valueOf(option.escape) + option.escape + lexStream.nameString(arrayElementTypeIndex)%><%
                }
                else if (classnameIndex != 0 && arrayElementTypeIndex != 0)
                {
                    %><%=lexStream.nameString(classnameIndex) + option.escape + lexStream.nameString(arrayElementTypeIndex)%><%
                }
                else
                    assert (classnameIndex == 0 && arrayElementTypeIndex == 0);

                if (ruleElement.isArrowProduction())
                    %>-><%
                else
                    %>::=<%
                alternateSpace = writer.getCurrentColumn() - 2;
            }
            writer.setIndentSize(writer.getCurrentColumn() + 1);

            for (int i = lexStream.next(rule.separatorIndex); i < rule.endRhsIndex; i = lexStream.next(i))
            {
                int kind = lexStream.kind(i);
                if (kind == Lpgsym.TK_SYMBOL)
                    displaySymbol(lexStream.nameString(i));
                else if (kind == Lpgsym.TK_MACRO_NAME)
                {
                    %><%=lexStream.nameString(i)%><%
                }
                else if (kind == Lpgsym.TK_EMPTY_KEY)
                {
                    %><%=option.escape + "Empty"%><%
                }
            }
            writer.endAutoWrap();
        }

        //
        // Print the Types
        //
        if (!parser.types.isEmpty())
        {
            %>


Types:
<%
            alternateSpace = 0;
            for (int i = 0, n = parser.types.size(); i < n; i++)
            {
                TypeDefinition type = parser.types.get(i);
                %>
    <%
                writer.beginAutoWrap();
                if (lexStream.kind(type.separatorIndex) == Lpgsym.TK_OR_MARKER)
                {
                    writer.padToColumn(alternateSpace);
                    %><%=option.orMarker%><%
                }
                else
                {
                    %><%=lexStream.nameString(type.typeIndex)%>::=<%
                    alternateSpace = writer.getCurrentColumn() - 2;
                }
                %><%=lexStream.nameString(type.symbolIndex)%><%
                writer.endAutoWrap();
            }
        }

        //
        // Print the Names
        //
        if (option.errorMaps)
        {
            %>


Name map:

<%
            for (int symbol = 1; symbol <= grammar.numSymbols; symbol++)
            {
                if (grammar.symbolIndex.get(symbol).externalNameIndex !=
                        grammar.symbolIndex.get(grammar.acceptImage).externalNameIndex)
                {
                    displayNameMap(symbol);
                }
            }
    
            for (int symbol = 1; symbol <= grammar.numSymbols; symbol++)
            {
                if (symbol != grammar.acceptImage && grammar.symbolIndex.get(symbol).externalNameIndex ==
                        grammar.symbolIndex.get(grammar.acceptImage).externalNameIndex)
                {
                    displayNameMap(symbol);
                }
            }
        }
        %>
<%!
    private DispatchWriter writer = null;

    private Control control = null;
    private Option option = null;
    private LexStream lexStream = null;
    private LookupTable<String, MacroSymbol> macroTable = null;
    private Grammar grammar = null;
    private Parser parser = null;

    private Action action = null;

    void setParameters(Control control, Action action)
    {
        this.control = control;
        this.action = action;

        option = control.option;
        lexStream = control.lexStream;
        macroTable = control.macroTable;
        grammar = control.grammar;
        parser = grammar.parser;

        setOut(option._syslis);
        writer = option._syslis;
    }

    private void displaySymbol(String name)
    {
        int length = name.length();
        if (name.equals("\"")   || name.equals(" ")    || name.equals("--")   || name.equals("|") ||
            name.equals("::=")  || name.equals("::=?") || name.equals("->")   || name.equals("->?"))
        {
            %><%='\'' + name + '\''%><%
        }
        else if (name.charAt(0) == '<' && name.charAt(length - 1) == '>')
        {
            %><%=name%><%
        }
        else if (name.equals("'")) // a string consisting of 1 single quote
        {
            %>"'"<%
        }
        else if (name.indexOf('"') != -1)
        {
            %><%=Utility.escape(name, '\'')%><%
        }
        else if (Util.containsChar(name, "\b\t\n\f\r' "))
        {
            %><%=Utility.escape(name, '"')%><%
        }
        else if (name.charAt(0) == option.escape || name.charAt(0) == '%') // does name start with user-escape or keyword-escape?
        {
            %><%='\'' + name + '\''%><%
        }
        else
        {
            %><%=name%><%
        }
    }

    //
    // This procedure prints the name associated with a given symbol.
    //
    private void displayNameMap(int symbol)
    {
        %>
<%
        writer.beginAutoWrap();
        %><%=grammar.retrieveString(symbol)%>::=<%=grammar.retrieveName(symbol)%><%
        writer.endAutoWrap();
    }
%>
